package com.example.appiumautotest.controller;

import com.example.appiumautotest.emun.TestCase;
import com.example.appiumautotest.utils.ConfigInfo;
import com.example.appiumautotest.utils.InitConnectInfo;
import com.example.appiumautotest.utils.POIHandle;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.touch.WaitOptions;
import io.appium.java_client.touch.offset.PointOption;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class StartMain {

    @Autowired
    private InitConnectInfo initConnectInfo;
    @Autowired
    private ConfigInfo configInfo;
    @Autowired
    private POIHandle poiHandle;

    @Autowired
    private Environment environment;

    int num = 0;
    Actions actions;

    // 启动方法 入口
    public void start() {

        // 获取连接信息
        String serverUrl = environment.getProperty("myConfigInfo.serverUrl");
        String platform = environment.getProperty("myConfigInfo.platform");
        String version = environment.getProperty("myConfigInfo.version");
        String deviceName = environment.getProperty("myConfigInfo.deviceName");
        String appPackage = environment.getProperty("myConfigInfo.appPackage");
        String appActivity = environment.getProperty("myConfigInfo.appActivity");

        // 填充所有连接信息和设置选项
        DesiredCapabilities capabilities = initConnectInfo.setConnectInfo(platform, version, deviceName, appPackage, appActivity);

        // 获得webdriver 设置连接超时时间
        AndroidDriver androidDriver = initConnectInfo.getAndroidDriver(serverUrl, capabilities);
        androidDriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        Dimension size = androidDriver.manage().window().getSize();
        configInfo.setHeight(size.getHeight());
        configInfo.setWidth(size.getWidth());
        actions = new Actions(androidDriver);

        // 执行测试用例
        try {
            runTestCase(androidDriver);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        log.info("执行时间：{}   共执行{}条用例", LocalDateTime.now(), num);
    }

    // 输出日志
    private void printLog(int index, XSSFSheet initSheet) {
        String logString = "";
        Iterator<Cell> iterator = poiHandle.getRow(initSheet, index).iterator();
        for (Iterator<Cell> it = iterator; it.hasNext(); ) {
            Object tmp = it.next();
            logString = logString + "  " + tmp.toString();
        }
        log.info("当前执行的事件：{}", logString);
    }

    // 执行测试用例
    private void runTestCase(AndroidDriver androidDriver) throws IOException {

        // 获取连接信息
        String testCaseFilePath = environment.getProperty("myConfigInfo.testCaseFilePath");
        Integer sheetIndex = Integer.valueOf(Objects.requireNonNull(environment.getProperty("myConfigInfo.sheetIndex")));

        // 记录执行结果，方便后续进行文档内容填充
        HashMap<Integer, Object> runResult = new HashMap<>();
        // 初始化sheet
        XSSFSheet initSheet = poiHandle.init(testCaseFilePath, sheetIndex);
        // 等待首页数据加载完毕
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 遍历执行
        for (int i = 1; i < poiHandle.getRowCount(initSheet); i++) {
            // 执行用例标题、用例的控件id、用例的输入内容
            String funType = poiHandle.getCell(initSheet, i, TestCase.METHODTYPE.getType()).getStringCellValue();
            String eventValue = poiHandle.getCell(initSheet, i, TestCase.CLICKING.getType()).getStringCellValue();
            String inputString = poiHandle.getCell(initSheet, i, TestCase.INPUT_STRING.getType()).getStringCellValue();
            // 判断事件类型
            switch (funType) {
                case "单击":
                    for (int j = 0; j < getEachCount(initSheet, i); j++) {
                        // 获取单击类型并执行
                        String searchType = ifSearchType(initSheet, i);
                        runClick(androidDriver, searchType, eventValue);
                        // 打印日志
                        printLog(i, initSheet);
                        // 填充测试结果（先记录，后续进行填充优化）
                        // runResult.put(i, true);
                        // testcase执行后的delay操作
                        runDelay(initSheet, i);
                    }
                    break;
                case "滑动":
                    for (int j = 0; j < getEachCount(initSheet, i); j++) {
                        // 获取滑动类型
                        String swipeType = poiHandle.getCell(initSheet, i, TestCase.EVENT_TYPE.getType()).getStringCellValue();
                        // 打印日志
                        printLog(i, initSheet);
                        runSwipe(androidDriver, swipeType);
                        // testcase执行后的delay操作
                        runDelay(initSheet, i);
                    }
                    break;
                case "输入":
                    for (int j = 0; j < getEachCount(initSheet, i); j++) {
                        // 获取滑动类型
                        String searchType = ifSearchType(initSheet, i);
                        // 打印日志
                        printLog(i, initSheet);
                        // 执行
                        runEntry(androidDriver, searchType, eventValue, inputString);
                        // testcase执行后的delay操作
                        runDelay(initSheet, i);
                    }
                    break;
                case "置后":
                    for (int j = 0; j < getEachCount(initSheet, i); j++) {
                        // 打印日志
                        printLog(i, initSheet);
                        // 执行
                        runBackground(androidDriver, Integer.valueOf(inputString));
                        // testcase执行后的delay操作
                        runDelay(initSheet, i);
                    }
                    break;
            }
            num++;
        }
    }

    // 执行滑动事件
    private void runSwipe(AndroidDriver androidDriver, String type) {

        TouchAction touchActions = new TouchAction(androidDriver);
        PointOption point = PointOption.point(configInfo.getWidth() / 2, configInfo.getHeight() / 2);

        if (type.toUpperCase().equals("UP")) {
            PointOption pointB = PointOption.point(configInfo.getWidth() / 2, 0);
            // 按压一秒然后移动到指定位置然后抬起
            touchActions.press(point).waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))).moveTo(pointB).release().perform();
            log.info("向上滑动");
        } else if (type.toUpperCase().equals("DOWN")) {
            PointOption pointB = PointOption.point(configInfo.getWidth() / 2, configInfo.getHeight());
            // 按压一秒然后移动到指定位置然后抬起
            touchActions.press(point).waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))).moveTo(pointB).release().perform();
            log.info("向下滑动");
        } else if (type.toUpperCase().equals("LEFT")) {
            PointOption pointB = PointOption.point(0, configInfo.getHeight() / 2);
            // 按压一秒然后移动到指定位置然后抬起
            touchActions.press(point).waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))).moveTo(pointB).release().perform();
            log.info("向左滑动");
        } else if (type.toUpperCase().equals("RIGHT")) {
            PointOption pointB = PointOption.point(configInfo.getWidth(), configInfo.getHeight() / 2);
            // 按压一秒然后移动到指定位置然后抬起
            touchActions.press(point).waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))).moveTo(pointB).release().perform();
            log.info("向右滑动");
        }
    }

    // 执行点击事件
    private void runClick(AndroidDriver androidDriver, String type, String clickValue) {
        if (type.equals("XPATH")) {
            androidDriver.findElementByXPath(clickValue).click();
        } else if (type.equals("ID")) {
            androidDriver.findElementById(clickValue).click();
        }
    }

    // 双击
    private void runDoubleClick(AndroidDriver androidDriver, String type, String clickValue) {
        if (type.equals("XPATH")) {
            actions.doubleClick(androidDriver.findElementByXPath(clickValue)).perform();
        } else if (type.equals("ID")) {
            actions.doubleClick(androidDriver.findElementById(clickValue)).perform();
        }
    }

    // 执行延迟操作
    private void runDelay(XSSFSheet initSheet, int i) {
        try {
            int delayTime = (int) poiHandle.getCell(initSheet, i, TestCase.DELAY_TIME.getType()).getNumericCellValue();
            log.info("延迟执行：{} 秒", delayTime);
            TimeUnit.SECONDS.sleep(delayTime);
        } catch (InterruptedException e) {
            throw new RuntimeException("执行延迟操作失败", e);
        }
    }

    // 执行输入事件
    private void runEntry(AndroidDriver androidDriver, String type, String eventValue, String sendKey) {
        if (type.equals("XPATH")) {
            androidDriver.findElementByXPath(eventValue).sendKeys(sendKey);
        } else if (type.equals("ID")) {
            androidDriver.findElementById(eventValue).sendKeys(sendKey);
        }
    }

    // 判断以那种方式进行element的查找
    private String ifSearchType(XSSFSheet initSheet, int i) {
        String stringCellValue = poiHandle.getCell(initSheet, i, TestCase.EVENT_TYPE.getType()).getStringCellValue();
        if (stringCellValue.toUpperCase().equals("ID")) {
            return "ID";
        } else if (stringCellValue.toUpperCase().equals("XPATH")) {
            return "XPATH";
        } else {
            throw new RuntimeException("不支持的事件类型" + ":" + stringCellValue.toUpperCase());
        }
    }

    // 获取循环次数
    private int getEachCount(XSSFSheet initSheet, int i) {
        double numericCellValue = poiHandle.getCell(initSheet, i, TestCase.EACH_COUNT.getType()).getNumericCellValue();
        return (int) numericCellValue;
    }

    // app置于后台
    private void runBackground(AndroidDriver androidDriver, int number) {
        log.info("应用置于后台{}秒后唤起", number);
        androidDriver.runAppInBackground(Duration.ofSeconds(number));
    }
}
